/*
 * xpfsm.c
 *
 *  Created on: 2/6/2010
 *      Author: apollo
 */
/******************************************************************************
 * <Includes>
 *****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xpdbg.h>
#include <xpfsm.h>
/******************************************************************************
 * <Defines>
 *****************************************************************************/

/******************************************************************************
 * <Typedefs>
 *****************************************************************************/

/******************************************************************************
 * <Local variables>
 *****************************************************************************/

/******************************************************************************
 * <Local declarations>
 *****************************************************************************/
/******************************************************************************
 * <Implementation>
 *****************************************************************************/
xpfsm_context* xpfsm_create()
{
    xpfsm_context *ctx;

    ctx = (xpfsm_context *)malloc(sizeof(xpfsm_context));
    XPASSERT(ctx != NULL)
    memset((void *)ctx, 0, sizeof(xpfsm_context));
    return ctx;
}

xpfsm_context* xpfsm_createx(xpfsm_state *stateTable, int initialState)
{
    xpfsm_context *ctx = xpfsm_create();

    ctx->stateTable = stateTable;
    ctx->curState = initialState;

    return ctx;
}

void xpfsm_delete(xpfsm_context *fsmCtx)
{
    free(fsmCtx);
}

void xpfsm_set_statetable(xpfsm_context *fsmCtx, xpfsm_state *stateTable)
{
    fsmCtx->stateTable = stateTable;
}

void xpfsm_set_transitiontable(xpfsm_context *fsmCtx, int state, xpfsm_transition *transitionTable)
{
    xpfsm_state *fsmState = &(fsmCtx->stateTable[state]);

    fsmState->transitionTable = transitionTable;
}

void xpfsm_process_event(xpfsm_context *fsmCtx, unsigned char e)
{
    xpfsm_state *curFsmState = &(fsmCtx->stateTable[fsmCtx->curState]);
    xpfsm_transition *fsmTransition = &(curFsmState->transitionTable[e]);

    XPASSERT(fsmTransition->destState != STATEMACHINE_ERROR)
    if (fsmCtx->curState == fsmTransition->destState)
        return;

    if (curFsmState->exitCallback != NULL)
        curFsmState->exitCallback(curFsmState->exitCallbackCtx);

    if (fsmCtx->transCallback != NULL)
        fsmCtx->transCallback(fsmCtx->transCallbackCtx);

    fsmCtx->curState = fsmTransition->destState;
    xpfsm_state *destFsmState = &(fsmCtx->stateTable[fsmTransition->destState]);

    if (destFsmState->enterCallback != NULL)
        destFsmState->enterCallback(destFsmState->enterCallbackCtx);
}

void xpfsm_set_state_enter(xpfsm_context *fsmCtx, int state, xpfsm_func enterCallback, xpfsm_func_context enterCallbackCtx)
{
    xpfsm_state *fsmState = &(fsmCtx->stateTable[state]);

    fsmState->enterCallback = enterCallback;
    fsmState->enterCallbackCtx = enterCallbackCtx;
}

void xpfsm_set_state_exit(xpfsm_context *fsmCtx, int state, xpfsm_func exitCallback, xpfsm_func_context exitCallbackCtx)
{
    xpfsm_state *fsmState = &(fsmCtx->stateTable[state]);

    fsmState->exitCallback = exitCallback;
    fsmState->exitCallbackCtx = exitCallbackCtx;
}

void xpfsm_set_transition_func(xpfsm_context *fsmCtx, xpfsm_func func, xpfsm_func_context funcCtx)
{
    fsmCtx->transCallback = func;
    fsmCtx->transCallbackCtx = funcCtx;
}

int xpfsm_get_state(xpfsm_context *fsmCtx)
{
    return fsmCtx->curState;
}

